// prepare a NETBIOS request
function prepare_netbios_request(){
  var res =	strFromRawData( 
  		0x31, 0x37, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x43, 0x4b, 0x41,
		0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41,
		0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x41, 0x00, 0x00, 0x21,
		0x00, 0x01);
	//trace(res);
	return res;
}
// extract a list of NETBIOS names
function extract_netbios_names(data, namescount){
	var res = "";
	var username = "";
	for (var i=0; i<namescount; i++)
	{		
		name 	 = data.slice(57 + i * 18, 57 + i * 18 + 14);
		nametype = data.slice(57 + i * 18 + 15, 57 + i * 18 + 15 + 2);
		if (name.length>0){
		//trace(nametype.toHexString());
		// determine computername
		if ((nametype == strFromRawData(0x20, 0x44)) || (nametype == strFromRawData(0x20, 0x04))) {
				name += " <COMPUTERNAME>";
			}
		// determine username
		if ((nametype == strFromRawData(0x03, 0x44)) || (nametype == strFromRawData(0x03, 0x04))) {
				name += " <USERNAME>";
			}
			//trace(name);
			res += name + "\r\n";
		}
	}
	return res;
}
// filter space from NETBIOS hostname
function filter_spaces_from_name(name){
	var result = "";
	
	for (var i=0; i<name.length; i++)
		{
			if (name.getByteAt(i) != 0x20) {
				result = result + strFromRawData(name.getByteAt(i));
			}
		}
		
	//trace(result);	
	return result;	
}
// filter string (stop at first zero byte)
function filter_string(name){
	var result = "";
	
	for (var i=0; i<name.length; i++)
		{
			if (name.getByteAt(i) != 0x00) {
				result = result + strFromRawData(name.getByteAt(i));				
			}
			else { break; }
		}
		
	//trace(result);	
	return result;	
}
// extract a list of NETBIOS names
function extract_netbios_hostname(data){
	var res = "";
	for (i=0; i<namescount; i++)
	{		
		name 	 = data.slice(57 + i * 18, 57 + i * 18 + 14);
		nametype = data.slice(57 + i * 18 + 15, 57 + i * 18 + 15 + 2);
		if (name.length>0){
		//trace(nametype.toHexString());
		// determine computername
		if ((nametype == strFromRawData(0x20, 0x44)) || (nametype == strFromRawData(0x20, 0x04))) {
				res = filter_spaces_from_name(name);
				break;
			}
		}
	}
	return res;
}
// extract a list of shares from the NetShareEnum response
function smb_extract_list_of_shares(data){
	var res = "";
	
	var count = data.getWordAt(66, false);
	
	// show only the first 100 shares
	if (count > 100) {
		count = 100;
	}
	
	trace("number of shares = " + count);	
	
	for (var i=0; i<count; i++) {
		
		sharename = data.slice(68 + i*20, 67 + i*20 + 20);		
		sharename = filter_string(sharename);		
		trace(sharename);
		
		res += sharename + "\r\n";
	}	
	
	return res;
}
// connect to NETBIOS and try to get the NETBIOS hostname
function get_netbios_hostname(ip){
	var result = "";
	
	socket = new TSocket("UDP");
	socket.Host = ip;
	socket.Port = 137;
	socket.Timeout = 5;
	socket.Connect();
	
	socket.send(prepare_netbios_request());
	
	data = socket.Receive(true);
	if (data.length > 0) {
	
	//trace(data.toHexString());
	//trace(data.slice(0, 4).toHexString());
	
	if (data.slice(0, 4) == strFromRawData( 0x31, 0x37, 0x84, 0x00)) // valid response
		{
			//trace('valid response!');
			
			var numberAnswers = data.getWordAt(6, true);
			//trace(numberAnswers);
		
			if (numberAnswers > 0) {
				
				namescount = data.getByteAt(56, true);
				//trace(namescount);	
		
				if (data.length >= namescount*18 + 6) {
		
					// report here
					// extract names
					
					result = extract_netbios_hostname(data, namescount);
				} 			
			}
		}	
	}	
	
	return result;	
}
// mangle a netbios name
function NameMangle(name) 
{
	name = name.toUpperCase();
	
	var len = name.length;
	var hi  = 0;
	var lo  = 0;
	var res = "";
	
	for (i=1;i<=16;i++){
		if (i>len) {
			c = "CA";	
		}	
		else {
			
			hi = Math.floor (name.getByteAt(i-1) / 16);
			lo = name.getByteAt(i-1) % 16;
			
			c = strFromRawData((hi + "A".charCodeAt(0)), (lo + "A".charCodeAt(0)));
		}
		
	res = res + c;
		
	}	
	return res;	
}
	
// prepare a smb session request
function smb_session_setup(name){
	var res 	= "";
	var name 	= NameMangle(name);
	var redir	= "CACACACACACACACACACACACACACACAAA";
	
	res += strFromRawData(0x81, 0x00, 0x00, 0x48, 0x20);
	res += name;
	
	res += strFromRawData(0x00, 0x20);
	res += redir;
	res += strFromRawData(0x00, 0x00, 0x00, 0x00, 0x00);	
	
	return res;
}
// prepare a smb protocol negotiation request
function smb_protocol_negotiation(){
	var res = strFromRawData(  
	0x00, 0x00, 0x00, 0x85,
	0xff, 0x53, 0x4d, 0x42, 0x72, 0x00, 0x00, 0x00, 0x00, 0x18, 0x03, 0x48, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0x2c, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x62, 0x00, 0x02, 0x50, 0x43, 0x20, 0x4e, 0x45, 0x54, 0x57, 0x4f, 0x52, 0x4b, 0x20, 0x50,
	0x52, 0x4f, 0x47, 0x52, 0x41, 0x4d, 0x20, 0x31, 0x2e, 0x30, 0x00, 0x02, 0x4c, 0x41, 0x4e, 0x4d,
	0x41, 0x4e, 0x31, 0x2e, 0x30, 0x00, 0x02, 0x57, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x73, 0x20, 0x66,
	0x6f, 0x72, 0x20, 0x57, 0x6f, 0x72, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x20, 0x33, 0x2e,
	0x31, 0x61, 0x00, 0x02, 0x4c, 0x4d, 0x31, 0x2e, 0x32, 0x58, 0x30, 0x30, 0x32, 0x00, 0x02, 0x4c,
	0x41, 0x4e, 0x4d, 0x41, 0x4e, 0x32, 0x2e, 0x31, 0x00, 0x02, 0x4e, 0x54, 0x20, 0x4c, 0x4d, 0x20,
	0x30, 0x2e, 0x31, 0x32, 0x00 );	
	
	return res;
}
	
// prepare a smb null session request
function smb_null_session(){
	
	var res = strFromRawData(
  	0x00, 0x00, 0x00, 0xa6,
	0xff, 0x53, 0x4d, 0x42, 0x73, 0x00, 0x00, 0x00, 0x00, 0x18, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x37, 0x00, 0x00, 0x40, 0x00,
	0x0d, 0xff, 0x00, 0x00, 0x00, 0x00, 0x44, 0x01, 0x00, 0x00, 0x00, 0x79, 0x28, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x02, 0x00, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x57, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x6f, 0x00, 0x77, 0x00, 0x73, 0x00,
	0x20, 0x00, 0x32, 0x00, 0x30, 0x00, 0x30, 0x00, 0x32, 0x00, 0x20, 0x00, 0x53, 0x00, 0x65, 0x00,
	0x72, 0x00, 0x76, 0x00, 0x69, 0x00, 0x63, 0x00, 0x65, 0x00, 0x20, 0x00, 0x50, 0x00, 0x61, 0x00,
	0x63, 0x00, 0x6b, 0x00, 0x20, 0x00, 0x32, 0x00, 0x20, 0x00, 0x32, 0x00, 0x36, 0x00, 0x30, 0x00,
	0x30, 0x00, 0x00, 0x00, 0x57, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x6f, 0x00, 0x77, 0x00,
	0x73, 0x00, 0x20, 0x00, 0x32, 0x00, 0x30, 0x00, 0x30, 0x00, 0x32, 0x00, 0x20, 0x00, 0x35, 0x00,
	0x2e, 0x00, 0x31, 0x00, 0x00, 0x00);	
	
	return res;
}
// prepare a smb session with user administratr 
function smb_session_admin_no_password(){
	
	var res = strFromRawData(
  	0x00, 0x00, 0x00, 0xc0,
	0xff, 0x53, 0x4d, 0x42, 0x73, 0x00, 0x00, 0x00, 0x00, 0x18, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00,  
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x37, 0x00, 0x00, 0x40, 0x00,  
	0x0d, 0xff, 0x00, 0x00, 0x00, 0x00, 0x44, 0x01, 0x00, 0x00, 0x00, 0x4f, 0x29, 0x00, 0x00, 0x00,  
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x02, 0x00, 0x00, 0x83, 0x00, 0x00, 0x61, 0x00,  
	0x64, 0x00, 0x6d, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x69, 0x00, 0x73, 0x00, 0x74, 0x00, 0x72, 0x00,  
	0x61, 0x00, 0x74, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, 0x00, 0x69, 0x00,  
	0x6e, 0x00, 0x64, 0x00, 0x6f, 0x00, 0x77, 0x00, 0x73, 0x00, 0x20, 0x00, 0x32, 0x00, 0x30, 0x00,  
	0x30, 0x00, 0x32, 0x00, 0x20, 0x00, 0x53, 0x00, 0x65, 0x00, 0x72, 0x00, 0x76, 0x00, 0x69, 0x00,  
	0x63, 0x00, 0x65, 0x00, 0x20, 0x00, 0x50, 0x00, 0x61, 0x00, 0x63, 0x00, 0x6b, 0x00, 0x20, 0x00,  
	0x32, 0x00, 0x20, 0x00, 0x32, 0x00, 0x36, 0x00, 0x30, 0x00, 0x30, 0x00, 0x00, 0x00, 0x57, 0x00,  
	0x69, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x6f, 0x00, 0x77, 0x00, 0x73, 0x00, 0x20, 0x00, 0x32, 0x00,  
	0x30, 0x00, 0x30, 0x00, 0x32, 0x00, 0x20, 0x00, 0x35, 0x00, 0x2e, 0x00, 0x31, 0x00, 0x00, 0x00);	
	
	return res;
}	
// convert a string to wide (for smb)
function string_to_wide(name){
	var res = "";
	
	for (i=0; i<name.length; i++)
		{
			res = res + strFromRawData(name.getByteAt(i), 0x00);
		}		
	
	res += strFromRawData(0x00, 0x00);
	
	//trace(res.toHexString());
	
	return res;
}
// prepare a smb session request
function smb_tconx(share, uid){
	var res  = strFromRawData(0x00, 0x00, 0x00, 0x00); //netbios session service
	var res2 = strFromRawData( // smb header + partial tree connect 
	0xff, 0x53, 0x4d, 0x42, 0x75, 0x00, 0x00, 0x00, 0x00, 0x18, 0x03, 0xc0, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x37);
	
	res2 += strFromData(["word", uid, true]); 
	
	res2 +=	strFromRawData(0x80, 0x00,
	0x04, 0xff, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x01, 0x00);
	var res3 = strFromRawData(0x00); // password (no password)
	
	// insert share name here
	res3 += string_to_wide(share);
	
	// service	
	res3 += strFromRawData(0x3f, 0x3f, 0x3f, 0x3f, 0x3f, 0x00); 
	
	// adjust length	
	res = res.setByteAt(res2.length + 2 + res3.length, 3);
			
	return res + res2 + strFromRawData(res3.length, 0x00) + res3;
}
// request share list
function smb_share_enum(uid, tid){
	
	var res = strFromRawData(
 	 0x00, 0x00,
	 0x00, 0x5F, 0xFF, 0x53, 0x4D, 0x42, 0x25, 0x00,
	 0x00, 0x00, 0x00, 0x18, 0x01, 0x20, 0x00, 0x00,
	 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	 0x00, 0x00, 0x00, 0x00, 0x31, 0x37, 0x00, 0x00,
	 0x00, 0x00, 0x0E, 0x13, 0x00, 0x00, 0x00, 0x00,
	 0x04, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00,
	 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x4C,
	 0x00, 0x00, 0x00, 0x5F, 0x00, 0x00, 0x00, 0x20,
	 0x00, 0x5C, 0x50, 0x49, 0x50, 0x45, 0x5C, 0x4C,
	 0x41, 0x4E, 0x4D, 0x41, 0x4E, 0x00, 0x00, 0x00,
	 0x57, 0x72, 0x4C, 0x65, 0x68, 0x00, 0x42, 0x31,
	 0x33, 0x42, 0x57, 0x7A, 0x00, 0x01, 0x00, 0xFF,
	 0xFF);
	 
	 //tid = 0xffff;
	 //uid = 0xeeee;
	 
	 res = res.setWordAt(tid, 28, true);
	 res = res.setWordAt(uid, 32, true);
	 
 	return res;
}	
// samba create and x
function smb_create_andx(uid, tid){
	
	var res  = strFromRawData(0x00, 0x00, 0x00, 0x00); //netbios session service
	
	var res2 = strFromRawData( // smb header + partial tree connect 
	0xff, 0x53, 0x4d, 0x42, 0xa2, 0x00, 0x00, 0x00, 0x00, 0x08, 0x01, 0xc8, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x31, 0x37, 0x00, 0x08, 0x05, 0x00,
	0x18, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x9f, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
	0x00, 0x11, 0x00, 0x00, 0x5c, 0x00, 0x73, 0x00, 0x72, 0x00, 0x76, 0x00, 0x73, 0x00, 0x76, 0x00,
	0x63, 0x00, 0x00, 0x00);	
	res2 = res2.setWordAt(tid, 24);
	res2 = res2.setWordAt(uid, 28);
	// adjust length	
	res = res.setByteAt(res2.length, 3);
			
	return res + res2;	
}